﻿using HmmmIDE.Syntax;
using System;
using System.Linq;
using System.Text.RegularExpressions;

namespace HmmmIDE.Intellisense
{
    /// <summary>
    /// Raw class for each instruction in document
    /// </summary>
    public class Instruction : IComparable
    {
        //public string Name { get; private set; }
        //public string Description { get; private set; }
        //public string Usage { get; set; }
        //public string Syntax { get; private set; }

        //public Register(string name, string description, string usage, string syntax)
        //{
        //    this.Name = name;
        //    this.Description = description;
        //    this.Usage = usage;
        //    this.Syntax = syntax;
        //}

        /// <summary>
        /// Raw text for an instruction. Also contains comment
        /// </summary>
        public string Text { get; set; }
        /// <summary>
        /// Line number in Text Editor. Please pay attention is a 1-based index
        /// </summary>
        public int LineNumber { get; set; }

        /// <summary>
        /// Used in identify instructions that need been tracked
        /// </summary>
        internal static string jumpPattern
        {
            get
            {
                var result = SyntaxManager.CommandRegex.Where((element => (element.Key[0] == 'j' || element.Key[0] == 'c') && (element.Key[element.Key.Length - 1] == 'n')));
                string value = "";
                foreach (var kvp in result)
                    value += kvp.Value + '|';
                return value.Substring(0, value.Length - 1);
            }
        }

        public Instruction(string text, int lineNumber)
        {
            this.Text = text;
            this.LineNumber = lineNumber;
        }
        /// <summary>
        /// Instruction number, i.e. line number in code (not in Text Editor)
        /// </summary>
        public int InstructionNumber
        {
            get
            {
                var match = Regex.Match(Text, @"^\d{1,}");
                return Int32.Parse(match.Value);
            }
            set
            {
                this.Text = Regex.Replace(this.Text, @"^\d{1,}", value.ToString());
            }
        }

        /// <summary>
        /// Line number that it referenced. Make it truly understand the reference
        /// </summary>
        public int ReferenceLineNumber
        {
            get
            {
                if(Regex.IsMatch(this.Text, jumpPattern))
                {
                    string result = Regex.Match(this.Text, @",?\s{1,}\d{1,}").Value;
                    result = Regex.Match(result, @"\d{1,2}").Value;
                    int num = 0;
                    if (int.TryParse(result, out num))
                        return num;
                }
                return -1;
            }
        }

        /// <summary>
        /// The name of command containing in the instruction
        /// </summary>
        public string CommandName
        {
            get
            {
                string[] result = Text.Split(new char[] { ',', ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
                return result[1];
            }
        }


        private bool CompareRegisters(Instruction other)
        {
            bool result = true;
            var matchThis = Regex.Matches(Text, @"r\d{1,2}");
            var matchOther = Regex.Matches(other.Text, @"r\d{1,2}");
            if (matchThis.Count != matchOther.Count) return false;
            for (int i = 0; i < matchThis.Count; i++ )
            {
                if(result)
                {
                    if (matchThis[i].Value != matchOther[i].Value)
                        result = false;
                }
            }
            return result;
        }
        /// <summary>
        /// Returns 0 if the two instructions are the same. Otherwise -1. Please do not use this to sort instructions
        /// </summary>
        /// <param name="obj">Instruction</param>
        /// <returns>0 if equal.</returns>
        public int CompareTo(Object obj)
        {
            Instruction instruction = obj as Instruction;
            if (instruction == null) return -1;
            if(this.CommandName == instruction.CommandName && CompareRegisters(instruction))
            {
                return 0;
            }
            return -1;
        }


        
    }
}
